package com.xianl.busiplat.dao;

import static org.springframework.util.Assert.notNull;
import java.lang.reflect.Constructor;
import org.apache.ibatis.executor.ErrorContext;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSession;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import org.springframework.beans.factory.FactoryBean;

public class PlatDaoFactoryBean<T> extends SqlSessionDaoSupport implements
		FactoryBean<T> {

	private Class<T> mapperInterface;

	private boolean addToConfig = true;
	
	private Class<T> impl;

	public void setMapperInterface(Class<T> mapperInterface) {
		this.mapperInterface = mapperInterface;
	}
	

	public void setImpl(Class<T> impl) {
		this.impl = impl;
	}


	public void setAddToConfig(boolean addToConfig) {
		this.addToConfig = addToConfig;
	}
	
	@Override
	protected void checkDaoConfig() {
		super.checkDaoConfig();

		notNull(this.mapperInterface, "Property 'mapperInterface' is required");

		Configuration configuration = getSqlSession().getConfiguration();
		if (this.addToConfig && !configuration.hasMapper(this.mapperInterface)) {
			try {
				configuration.addMapper(this.mapperInterface);
			} catch (Throwable t) {
				logger.error("Error while adding the mapper '"
						+ this.mapperInterface + "' to configuration.", t);
				throw new IllegalArgumentException(t);
			} finally {
				ErrorContext.instance().reset();
			}
		}
	}

	@Override
	public T getObject() throws Exception {
		if(impl != null && isImpl(impl, mapperInterface.getName())){
			logger.debug("custom Interface Impl instance");
			Constructor<T> con = impl.getConstructor(SqlSession.class);
			return con.newInstance(getSqlSession());
		}else{
			logger.debug("mybatis Impl instance");
			return getSqlSession().getMapper(this.mapperInterface);
		}
	}

	@Override
	public Class<?> getObjectType() {
		return this.mapperInterface;
	}

	@Override
	public boolean isSingleton() {
		return true;
	}

	/** 
	 * @param target
	 * @param interfaceName
	 * @return
	 */
	public static boolean isImpl(Class<?> target, String interfaceName){
		Class<?>[] faces = target.getInterfaces();
		for(Class<?> c : faces){
			if(c.getName().equals(interfaceName)){
				return true;
			}
		}
		return false;
	}
}
